package com.example.shiro.realm;

import com.example.shiro.entity.User;
import com.example.shiro.service.UserService;
import com.example.shiro.utils.ShiroPasswordUtil;
import org.apache.shiro.authc.*;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;

import java.util.HashSet;
import java.util.Set;

/**
 * @ClassName MyShiroRealm
 * @Description TODO
 * @Author WLJ
 * @Date 2025/9/18 20:07
 * @Version 1.0
 */
public class MyShiroRealm extends AuthorizingRealm {

    @Autowired
    private UserService userService;

    public MyShiroRealm() {
        // 设置凭证匹配器
        HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
        matcher.setHashAlgorithmName(ShiroPasswordUtil.ALGORITHM_NAME); // 加密方式与加密时一致
        matcher.setHashIterations(ShiroPasswordUtil.HASH_ITERATIONS); // 加密次数与加密时一致
        this.setCredentialsMatcher(matcher);
    }
    /*
     * @Description //TODO 获取用户角色及权限信息
     * @Params [principalCollection]
     * @return org.apache.shiro.authz.AuthorizationInfo
     * @version 1.0
     **/
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        // 从 PrincipalCollection 中获取登录用户的信息（在认证时存放的）
        String loginName = (String) principals.getPrimaryPrincipal();
        // 利用登录名查询用户的角色
        Set<String> roles = userService.findRoleCodesByLoginName(loginName);
        Set<String> permissions = new HashSet<>();

        if (!CollectionUtils.isEmpty(roles)) {
           // 根据角色编码查询权限信息
           permissions = userService.findResourceCodesByRoles(roles);
        }
        // 3. 创建 SimpleAuthorizationInfo 并设置 roles 和 permissions
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.setRoles(roles);
        info.setStringPermissions(permissions);
        return info;
    }
    /*
     * @Description //TODO 用户登录认证
     * @Params [authenticationToken]
     * @return org.apache.shiro.authc.AuthenticationInfo
     * @version 1.0
     **/
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        // 1. 把 AuthenticationToken 转换为 UsernamePasswordToken
        UsernamePasswordToken upToken = (UsernamePasswordToken) authenticationToken;

        // 2. 从 UsernamePasswordToken 中获取登录名
        String loginName = upToken.getUsername();

        // 3. 根据登录名从数据库查询用户信息。如果找不到，抛出 UnknownAccountException
        User user = userService.findByLoginName(loginName);
        if (user == null) {
            throw new UnknownAccountException("用户不存在！");
        }
        // 5. 构建 AuthenticationInfo 对象并返回。
        // 参数：principal（主体标识，通常是用户名或用户对象），credentials（从数据库查到的正确密码），credentialsSalt（密码加密后的盐值），realmName（当前 realm 的名称）
        // Shiro 会自动比较 token 中的密码（用户输入的）和这里返回的密码（数据库中的）是否一致。
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(
                user.getLoginName(), // principal 主体标识，通常放用户名或用户对象
                user.getPassword(), // hashedCredentials 数据库中的密码（已加密）
                ByteSource.Util.bytes(user.getSalt()), // 加密后的盐值
                getName() // realmName
        );
        return info;
    }
}
